package main

import (
	"fmt"
	"os"
	"path/filepath"
)

// global mode
var (
	IsDebugMode bool = false
	IsForceMode bool = false //Overwrite configuration file
)

// version info
var (
	VERSION     = "1.0"
	BUILDTIME   string
	BUILDCOMMIT string
	GOVERSION   string
)

func version() {
	fmt.Fprint(os.Stderr, "Banjo - Minimalist build and packaging tool\nversion:       ", VERSION, "\n",
		"build commit:  ", BUILDCOMMIT, "\n",
		"build time:    ", BUILDTIME, "\n",
		"go version:    ", GOVERSION, "\n")
}

func usage() {
	fmt.Fprintf(os.Stdout, `Bali - Minimalist build and packaging tool
usage: %s <option> args ...
  -h|--help        Show usage text and quit
  -v|--version     Show version number and quit
  -V|--verbose     Make the operation more talkative
  -F|--force       Turn on force mode. eg: Overwrite configuration file
  -c|--cwd         Build dir. (Position 0, default cwd)
  -a|--arch        Build arch: amd64 386 arm arm64
  -t|--target      Build target: windows linux darwin ...
  -o|--out         Build output dir. default '$CWD/build'
  -z|--zip         Create archive file after successful build
  -m|--mkstgz      After successful build, create STGZ installation package
  -d|--dist        STGZ/TarGz package distribution directory

`, os.Args[0])
}

// DbgPrint todo
func DbgPrint(format string, a ...interface{}) {
	if IsDebugMode {
		ss := fmt.Sprintf(format, a...)
		_, _ = os.Stderr.WriteString(StrCat("\x1b[33m* ", ss, "\x1b[0m\n"))
	}
}

// Invoke todo
func (be *BaliExecutor) Invoke(val int, oa, raw string) error {
	switch val {
	case 'h':
		usage()
		os.Exit(0)
	case 'v':
		version()
		os.Exit(0)
	case 'c':
		be.Cwd = oa
	case 'a':
		be.Arch = oa
	case 't': // target
		be.Target = oa
	case 'V':
		IsDebugMode = true
	case 'f': // --force
		IsForceMode = true
	case 'o': // --out
		be.Out = oa
	case 'd':
		be.Dist = oa
	case 'z': // --zip
		be.Zip = true
	case 'm': // --mkstgz
		be.Mkstgz = true
	default:
	}
	return nil
}

// ParseArgv todo
func (be *BaliExecutor) ParseArgv() error {
	var ae ArgvEngine
	ae.Add("help", NOARG, 'h')
	ae.Add("version", NOARG, 'v')
	ae.Add("verbose", NOARG, 'V')
	ae.Add("force", NOARG, 'f')
	ae.Add("cwd", REQUIRED, 'c')
	ae.Add("arch", REQUIRED, 'a')
	ae.Add("target", REQUIRED, 't')
	ae.Add("out", REQUIRED, 'o')
	ae.Add("dist", REQUIRED, 'd')
	ae.Add("zip", NOARG, 'z')
	ae.Add("mkstgz", NOARG, 'm')
	if err := ae.Execute(os.Args, be); err != nil {
		return err
	}
	if len(be.Cwd) == 0 {
		if len(ae.Unresolved()) > 0 {
			cwd, err := filepath.Abs(ae.Unresolved()[0])
			if err != nil {
				return err
			}
			be.Cwd = cwd
		} else {
			cwd, err := os.Getwd()
			if err != nil {
				return err
			}
			be.Cwd = cwd
		}
	}
	// set build out dir
	if len(be.Out) != 0 {
		if filepath.IsAbs(be.Out) {
			be.Out = filepath.Clean(be.Out)
		} else {
			be.Out = filepath.Join(be.Cwd, be.Out)
		}
	} else {
		be.Out = filepath.Join(be.Cwd, "build")
	}
	if len(be.Dist) == 0 {
		be.Dist = be.Cwd
	}
	return nil
}

func main() {
	var be BaliExecutor
	if err := be.ParseArgv(); err != nil {
		fmt.Fprintf(os.Stderr, "bali: \x1b[31m%v\x1b[0m\n", err)
		os.Exit(1)
	}
	if err := be.Initialize(); err != nil {
		fmt.Fprintf(os.Stderr, "bali: \x1b[31m%v\x1b[0m\n", err)
		os.Exit(1)
	}
	DbgPrint("build dir %s", be.Cwd)
	if err := be.CompileAll(); err != nil {
		os.Exit(1)
	}
	if err := be.FileInstall(); err != nil {
		fmt.Fprintf(os.Stderr, "bali: \x1b[31m%v\x1b[0m\n", err)
		os.Exit(1)
	}
	if be.Zip {
		if be.Target == "windows" {
			if err := be.CompressZip(); err != nil {
				fmt.Fprintf(os.Stderr, "bali: \x1b[31m%v\x1b[0m\n", err)
				os.Exit(1)
			}
			os.Exit(0)
		}
		if err := be.CompressTarGz(); err != nil {
			fmt.Fprintf(os.Stderr, "bali: \x1b[31m%v\x1b[0m\n", err)
			os.Exit(1)
		}
		os.Exit(0)
	}
	if !be.Mkstgz {
		os.Exit(0)
	}
	fmt.Fprintf(os.Stderr, "bali begin create \x1b[32mSTGZ\x1b[0m install package\n")
	if err := be.PackageCompress(); err != nil {
		fmt.Fprintf(os.Stderr, "bali: \x1b[31m%v\x1b[0m\n", err)
		os.Exit(1)
	}
}
